<?php
/* PHP SDK
 * @version 2.0.0
 * @author connect@qq.com
 * @copyright © 2013, Tencent Corporation. All rights reserved.
 * 
 * 方法集
 * 
 * 错误码
 * http://wiki.connect.qq.com/%E5%85%AC%E5%85%B1%E8%BF%94%E5%9B%9E%E7%A0%81%E8%AF%B4%E6%98%8E
 */
//引用
require_once(CLASS_PATH."Recorder.class.php");
require_once(CLASS_PATH."URL.class.php");
require_once(CLASS_PATH."ErrorCase.class.php");

class Oauth{

    const VERSION = "2.0";
    //使用Authorization_Code获取Access_Token
    const GET_AUTH_CODE_URL = "https://graph.qq.com/oauth2.0/authorize";#获取Authorization Code
    const GET_ACCESS_TOKEN_URL = "https://graph.qq.com/oauth2.0/token";#通过Authorization Code获取Access Token
    #权限自动续期，获取Access Token
    
    
    //此接口用于获取个人信息
    const GET_OPENID_URL = "https://graph.qq.com/oauth2.0/me";

    public $recorder;
    public $urlUtils;
    protected $error;
    

    function __construct(){
    	
    	     //data
        $this->recorder = new Recorder();
        //get、post
        $this->urlUtils = new URL();
        
        $this->error = new ErrorCase();
    }


/*
 * 
 * 获取Authorization Code
 * 
 * 通过config跳转到官方提供的登陆界面
 * 
 * 登陆之后会跳转到本站
 * 
 * 以get方式传递code到qqapi
 * 
 * 此code会在10分钟内过期
 * 
 */
    public function qq_login(){
    	//config
        $appid = $this->recorder->readInc("appid");
        $callback = $this->recorder->readInc("callback");
        $scope = $this->recorder->readInc("scope");

        //-------生成唯一随机串防CSRF攻击
        $state = md5(uniqid(rand(), TRUE));
       //static arr
        $this->recorder->write('state',$state);

        //-------构造请求参数列表
        $keysArr = array(
            "response_type" => "code",
            "client_id" => $appid,
            "redirect_uri" => $callback,
            "state" => $state,
            "scope" => $scope
        );
//拼接url
        $login_url =  $this->urlUtils->combineURL(self::GET_AUTH_CODE_URL, $keysArr);
//跳转到QQ提供的登陆界面
        header("Location:$login_url");
    }


/*
 * qq登陆之后，返回页面触发的函数
 * 
 * 通过Authorization Code获取Access Token
 * 
 * 根据config和get到的state、code，获取at
 * 
 * 同一code只允许调用一次
 * 
 * 
 * 
 * http://wiki.connect.qq.com/%E4%BD%BF%E7%94%A8authorization_code%E8%8E%B7%E5%8F%96access_token
 * 
 */
    public function qq_callback(){
    	
     	//static arr
        $state = $this->recorder->read("state");


        //--------验证state防止CSRF攻击
        if(!$state || $_GET['state'] != $state){
            $this->error->showError("30001");
        }

        //-------请求参数列表
        $keysArr = array(
            "grant_type" => "authorization_code",
            "client_id" => $this->recorder->readInc("appid"),
            "redirect_uri" => urlencode($this->recorder->readInc("callback")),
            "client_secret" => $this->recorder->readInc("appkey"),
            "code" => $_GET['code']
        );

        //拼接url，获取内容
        $response = $this->urlUtils->get(self::GET_ACCESS_TOKEN_URL, $keysArr);
        
//      var_dump($response);
        //出错
        if(strpos($response, "callback") !== false){

            $lpos = strpos($response, "(");
            $rpos = strrpos($response, ")");
            $response  = substr($response, $lpos + 1, $rpos - $lpos -1);
            $msg = json_decode($response);

            if(isset($msg->error)){
                $this->error->showError($msg->error, $msg->error_description);
            }
        }
        
        //成功
        $params = array();
        
        //将返回值加载到$params
        parse_str($response, $params);

//static arr
        $this->recorder->write("access_token", $params["access_token"]);#at
         $this->recorder->write("expires_in", $params["access_token"]);#at有效期（秒）
          $this->recorder->write("refresh_token", $params["access_token"]);#在授权自动续期步骤中，获取新的Access_Token时需要提供的参数
          
        return $params["access_token"];

    }


/*
 * 
 * 权限自动续期，获取Access Token
 * 
 * Access_Token的有效期默认是3个月，过期后需要用户重新授权才能获得新的Access_Token。本步骤可以实现授权自动续期，避免要求用户再次授权的操作，提升用户体验。
 * 
 * 
 * http://wiki.connect.qq.com/%E4%BD%BF%E7%94%A8authorization_code%E8%8E%B7%E5%8F%96access_token
 * 
 */

  public function at_refresh(){
    	
        //static arr
        $refresh_token = $this->recorder->read("refresh_token");
        //-------请求参数列表
        $keysArr = array(
            "grant_type" => "refresh_token",
            "client_id" => $this->recorder->readInc("appid"),
            "client_secret" => $this->recorder->readInc("appkey"),
            "refresh_token" =>$refresh_token
        );

        //拼接url，获取内容
        $response = $this->urlUtils->get(self::GET_ACCESS_TOKEN_URL, $keysArr);
        
        
        //出错
        if(strpos($response, "callback") !== false){

            $lpos = strpos($response, "(");
            $rpos = strrpos($response, ")");
            $response  = substr($response, $lpos + 1, $rpos - $lpos -1);
            $msg = json_decode($response);

            if(isset($msg->error)){
                $this->error->showError($msg->error, $msg->error_description);
            }
        }
        
        //成功
        $params = array();
        
        //将返回值加载到$params
        parse_str($response, $params);

//static arr
        $this->recorder->write("access_token", $params["access_token"]);#at
         $this->recorder->write("expires_in", $params["access_token"]);#at有效期（秒）
          $this->recorder->write("refresh_token", $params["access_token"]);#在授权自动续期步骤中，获取新的Access_Token时需要提供的参数
          
        return $params["access_token"];

    }



/*
 * 
 * 获取用户OpenID_OAuth2.0
 * 
 * 根据at获取openid
 * 
 * http://wiki.connect.qq.com/%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7openid_oauth2-0
 */
    public function get_openid(){

        //-------请求参数列表
        $keysArr = array(
            "access_token" => $this->recorder->read("access_token")
        );

        $response = $this->urlUtils->get(self::GET_OPENID_URL, $keysArr);
       

        //err
        if(strpos($response, "callback") !== false){

            $lpos = strpos($response, "(");
            $rpos = strrpos($response, ")");
            $response = substr($response, $lpos + 1, $rpos - $lpos -1);
        }

//success
        $user = json_decode($response);
        
        //err
        if(isset($user->error)){
            $this->error->showError($user->error, $user->error_description);
        }

        //static arr
        $this->recorder->write("openid", $user->openid);
        return $user->openid;

    }
}
